﻿using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;

namespace lox_z12Class
{
    abstract public class Expr
    {
        //访问者类，会实现Visitor。 然后，
        public interface Visitor<R> 
        {
            R visitAssignExpr(Assign expr);
            R visitBinaryExpr(Binary expr);
            R visitCallExpr(Call expr);
            R visitGetExpr(Get expr);
            R visitGroupingExpr(Grouping expr);
            R visitLiteralExpr(Literal expr);
            R visitLogicalExpr(Logical expr);
            R visitSetExpr(Set expr);
            R visitThisExpr(This expr);
            R visitUnaryExpr(Unary expr);

            R visitVariableExpr(Variable expr);
        }
        //定义一个抽象函数。 子类必须override它
        public abstract R accept<R>(Visitor<R> visitor);

        // Nested Expr classes here...
        //> expr-assign
        public class Assign : Expr
        {
            public Assign(Token name, Expr value)
            {
                this.name = name;
                this.value = value;
            }
            public override R accept<R>(Visitor<R> visitor)
            {
                return visitor.visitAssignExpr(this);
            }
            public Token name;
            public Expr value;
        }
        //< expr-assign

        // Nested Expr classes here...
        //> expr-binary
        public class Binary : Expr
        {
            public Binary(Expr left, Token pOperator, Expr right)
            {
                this.left = left;
                this._operator = pOperator;
                this.right = right;
            }

            public override R accept<R>(Visitor<R> visitor)
            { 
                return visitor.visitBinaryExpr(this); 
            }

            public Expr left;
            public Token _operator;
            public Expr right;
        }
        //< expr-binary
        //> expr-call
        public class Call : Expr
        {
            public Call(Expr callee, Token paren, List<Expr> arguments)
            {
                this.callee = callee;
                this.paren = paren;
                this.arguments = arguments;
            }

            public override R accept<R>(Visitor<R> visitor) { return visitor.visitCallExpr(this); }

            public Expr callee;
            public Token paren;
            public List<Expr> arguments;
        }
        //< expr-call
        //> expr-get
        public class Get : Expr
        {
            public Get(Expr pObject, Token name)
            {
                this._object = pObject;
                this.name = name;
            }

            public override R accept<R>(Visitor<R> visitor) { return visitor.visitGetExpr(this); }

            public Expr _object;
            public Token name;
        }
        //< expr-get
        //> expr-grouping
        public class Grouping : Expr
        {
            public Grouping(Expr expression) { this.expression = expression; }

            public override R accept<R>(Visitor<R> visitor) 
            { 
                return visitor.visitGroupingExpr(this); 
            }

            public Expr expression;
        }
        //< expr-grouping
        //> expr-literal
        public class Literal : Expr
        {
            public Literal(Object value) { this.value = value; }

            public override R accept<R>(Visitor<R> visitor) 
            { 
                return visitor.visitLiteralExpr(this); 
            }

            public Object value;
        }
        //< expr-literal
         //> expr-logical
        public class Logical : Expr
        {
            public Logical(Expr left, Token pOperator, Expr right)
            {
                this.left = left;
                this._operator = pOperator;
                this.right = right;
            }

            public override R accept<R>(Visitor<R> visitor) { return visitor.visitLogicalExpr(this); }

            public Expr left;
            public Token _operator;
            public Expr right;
        }
        //< expr-logical
        //> expr-set
        public class Set : Expr
        {
            public Set(Expr pObject, Token name, Expr value)
            {
                this._object = pObject;
                this.name = name;
                this.value = value;
            }

            public override R accept<R>(Visitor<R> visitor) { return visitor.visitSetExpr(this); }

            public Expr _object;
            public Token name;
            public Expr value;
        }
        //< expr-set
        //> expr-this
        public class This : Expr
        {
            public This(Token keyword) { this.keyword = keyword; }

            public override R accept<R>(Visitor<R> visitor) { return visitor.visitThisExpr(this); }

            public Token keyword;
        }
        //< expr-this
        //> expr-unary
        public class Unary : Expr
        {
            public Unary(Token pOperator, Expr right)
            {
                this._operator = pOperator;
                this.right = right;
            }

            public override R accept<R>(Visitor<R> visitor) 
            {
                return visitor.visitUnaryExpr(this); 
            }

            public Token _operator;
            public Expr right;
        }
        //< expr-unary

        //> expr-variable
        public class Variable : Expr
        {
            public Variable(Token name) { this.name = name; }

            public override R accept<R>(Visitor<R> visitor) 
            { 
                return visitor.visitVariableExpr(this);
            }

            public Token name;
        }
        //< expr-variable
    }
}
